package jgrit.gui.export;

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Document;

import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.factories.ComponentFactory;
import com.jgoodies.forms.factories.DefaultComponentFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import jgrit.JGritProperties;
import jgrit.gui.factory.TaskPanelFactory;
import jgrit.options.OptionCollection;
import static jgrit.Constants.*;

/**
 * Creates a frame based upon the options list
 * 
 * @author Derek Olejnik
 */
public class GBAExportTaskStyle extends ExportDialog {
	private static final long serialVersionUID = -3677851514352582791L;
	
	/***************************************************************************
	 * 								 VARIABLES
	 **************************************************************************/
	
	private static final String[] TASK_LIST = new String[]{"Mode 3 Bitmap", 
			"Mode 4 Palette Bitmap", "Mode 0 Tiles", "Mode 0 Sprites"};
	private static final String[] TASK_MESSAGE = new String[] {
		"This is the simplest of tasks. Exports graphics as a 15-bit RGB image (actually 16, but 1 isn't used). (Commonly used for a truecolor splash screen)",
		"Exports graphics as a palette of colors combined with 8-bit references into the palette array. (Commonly used for sprites)",
		"Exports graphics as a tile-based map utilizing a palette for colors within the tiles. Should ideally use 4/8 bit depth. (Commonly used for building maps)",
		"Exports graphics as a series of tiles. Sprites can be made of one or more such tiles. (Commonly used for sprites)"
	};
	
	//GUI components
	private JPanel mainPanel, taskPanel;
	private JTextPane announcementPane, contextHelp;
	private JScrollPane taskScrollPane;
	private JList taskList;
	private JButton advancedButton;
	private JLabel taskListLabel, taskPaneLabel;
	
	//Task Panels
	private Component mode3Bitmap, mode4PaletteBitmap, mode0Tilemap, mode0PaletteTiles;

	/***************************************************************************
	 * 							   CONSTRUCTORS
	 **************************************************************************/
	
	/**
	 * @throws HeadlessException
	 */
	public GBAExportTaskStyle() throws HeadlessException {
		super();		
		initGUI();
	}
	
	/**
	 * Creates this if there is already an advanced parent
	 * @param advancedParent - Advanced GUI parent window
	 */
	public GBAExportTaskStyle(GBAExportAdvanced otherGUI) {
		super(otherGUI);
		initGUI();
	}
	
	/**
	 * Creates the gui with a given options collection already created
	 * @param options
	 * @throws HeadlessException
	 */
	public GBAExportTaskStyle(OptionCollection options, Frame owner,
			String title, boolean modal) throws HeadlessException {
		super(options, owner, title, modal);
		initGUI();
	}
	
	/***************************************************************************
	 * 							  HELPER METHODS
	 **************************************************************************/
	
	/**
	 * Initializes the GUI, duh
	 */
	private void initGUI() {
		try {
			setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
			this.setTitle("GBA Export");
			
			initTaskPanels();
			initLayout();
			if (SHOW_ANNOUNCEMENT) {
				initAnnouncement();
			}
			initContextHelp();
			initTaskList();
			initTaskPanel();
			initButtons();
			initLabels();
			pack();
			taskList.requestFocusInWindow(); //Has to be done after a packing
			
			if (otherGUI == null) {
				otherGUI = new GBAExportAdvanced(this);
			}
			
			setLocationRelativeTo(getOwner());
		} catch (Exception e) {
			System.err.println("ERROR INITIALIZING GUI");
			e.printStackTrace();
		}
	}
	
	/**
	 * Initializes the task panels
	 */
	private void initTaskPanels() {
		mode3Bitmap = TaskPanelFactory.createMode3TaskPanel(SETTINGS);
		mode4PaletteBitmap = TaskPanelFactory.createMode4TaskPanel(SETTINGS);
		mode0Tilemap = TaskPanelFactory.createMode0TileMapTaskPanel(SETTINGS);
		mode0PaletteTiles = TaskPanelFactory
				.createMode0SpritesTaskPanel(SETTINGS);
	}
	
	/**
	 * Sets up the layout for the window (lays out the containers)
	 */
	private void initLayout() {
		mainPanel = new JPanel();
//		mainPanel = new FormDebugPanel();
		
		//7 columns and 10 rows
		FormLayout mainPanelLayout = new FormLayout(
				"$dmargin, max(p;$ugap), $rgap, max(p;$ugap):grow, $rgap, max(p;$ugap), $dmargin", //Columns
				"pref, $rgap, max(p;$ugap), $rgap, [25dlu,p,25dlu], $rgap, max(p;$ugap):grow, $rgap, max(p;$ugap), $dmargin" //Rows
				);
		mainPanel.setLayout(mainPanelLayout);
		
		//Add the main panel and pack to the main GUI
		getContentPane().add(mainPanel, BorderLayout.CENTER);
	}
	
	/**
	 * Initialize the announcement bar on the top of the window
	 * @throws BadLocationException 
	 */
	private void initAnnouncement() throws BadLocationException{
		announcementPane = new JTextPane();
		Document textBackend = new DefaultStyledDocument();
		textBackend.insertString(0, ANNOUNCEMENT, announcementPane.getStyle("default"));
		announcementPane.setDocument(textBackend);
		announcementPane.setEditable(false);
		
		//Add to the GUI
		mainPanel.add(announcementPane, 
				new CellConstraints("1,1,7,1,fill,fill"));
	}
	
	/**
	 * Initialize the announcement bar on the top of the window
	 * @throws BadLocationException 
	 */
	private void initContextHelp() {
		contextHelp = new JTextPane();
		setContextText(0);
		contextHelp.setEditable(false);
		//Have to set preferred size to as small as possible because it's
		//stretching out the window
		contextHelp.setPreferredSize(new Dimension());
		
		//Make it scrollable
		JScrollPane helperScrollPane = new JScrollPane();
		helperScrollPane.setViewportView(contextHelp);
		
		//Add to the GUI
		mainPanel.add(helperScrollPane, 
				new CellConstraints("4,5,3,1,fill,fill"));
	}
	
	/**
	 * Sets the context sensitive text
	 * @param indexOfList
	 */
	private void setContextText(int indexOfList) {
		Document textBackend = new DefaultStyledDocument();
		try {
			textBackend.insertString(0, TASK_MESSAGE[indexOfList], 
					contextHelp.getStyle("default"));
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
		contextHelp.setDocument(textBackend);
	}
	
	/**
	 * Sets up the task list for the left-hand side
	 */
	private void initTaskList() {
		taskScrollPane = new JScrollPane();
		ListModel taskListModel = new DefaultComboBoxModel(TASK_LIST);
		taskList = new JList();
		taskScrollPane.setViewportView(taskList);
		taskList.setModel(taskListModel);
		taskList.setSelectedIndex(0);
		taskList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		
		//Setup the listeners to the selections for switching the main view
		taskList.addListSelectionListener(new ListSelectionListener() {
			public void valueChanged(ListSelectionEvent e) {
				int selectedIndex = taskList.getSelectedIndex();
				//Set the title and panel to the proper item for this
				taskPaneLabel.setText(TASK_LIST[selectedIndex]);
				((CardLayout)taskPanel.getLayout()).show(taskPanel, TASK_LIST[selectedIndex]);
				
				updateOptions();
			}
		});
		
		//Add to the GUI
		mainPanel.add(taskScrollPane, 
				new CellConstraints("2,5,1,3,fill,fill"));
	}
	
	//Updates the options based upon what is selected in the task pane
	private void updateOptions() {
		int selectedIndex = taskList.getSelectedIndex();
		setContextText(selectedIndex);
		
		//Change any settings needed in the options for the task
		switch(selectedIndex) {
			case 0: //Mode 3 Bitmap
				SETTINGS.format.setValue(GFXFORMAT_BITMAP_GBA);
				SETTINGS.bitDepth.setValue("16");
				SETTINGS.graphicsCompression.setValue(COMPRESSION_OFF);
				SETTINGS.paletteEnabled.setValue("false");
				break;
			case 1: //Mode 4 Palette Bitmap
				SETTINGS.format.setValue(GFXFORMAT_BITMAP_GBA);
				SETTINGS.bitDepth.setValue("8");
				SETTINGS.graphicsCompression.setValue(COMPRESSION_OFF);
				SETTINGS.mapLayout.setValue(MAPLAYOUT_OFF);
				SETTINGS.paletteEnabled.setValue("true");
				break;
			case 2: //Mode 0 Tiles
				SETTINGS.format.setValue(GFXFORMAT_TILE);
				SETTINGS.bitDepth.setValue("8");
				SETTINGS.graphicsCompression.setValue(COMPRESSION_OFF);
				SETTINGS.mapLayout.setValue(MAPLAYOUT_FLAT);
				SETTINGS.paletteEnabled.setValue("true");
				break;
			case 3: //Mode 0 Sprites
				SETTINGS.format.setValue(GFXFORMAT_TILE);
				SETTINGS.bitDepth.setValue("8");
				SETTINGS.graphicsCompression.setValue(COMPRESSION_OFF);
				SETTINGS.mapLayout.setValue(MAPLAYOUT_OFF);
				SETTINGS.paletteEnabled.setValue("true");
				break;
			default:;
		}		
	}
	
	/**
	 * Setup the buttons (Advanced, Ok, and Cancel)
	 */
	protected void initButtons() {
		super.initButtons();
		advancedButton = new JButton("Advanced...");
		
		//Setup action listeners
		advancedButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ExportDialog.inst = otherGUI;
				otherGUI.setVisible(true);
				GBAExportTaskStyle.this.setVisible(false);
			}
		});
		
		//Add to the GUI
		mainPanel.add(advancedButton, new CellConstraints("2,9,1,1,fill,fill"));
		mainPanel.add(ButtonBarFactory.buildOKCancelBar(okButton, cancelButton),
				new CellConstraints("6,9,1,1,fill,fill"));
	}
	
	/**
	 * Sets up the main task panel in the center of the GUI
	 */
	public void initTaskPanel() {
		taskPanel = new JPanel();
		taskPanel.setBorder(BorderFactory.createEtchedBorder());
		CardLayout taskPanelLayout = new CardLayout();
		taskPanelLayout.setHgap(5);
		taskPanelLayout.setVgap(5);
		taskPanel.setLayout(taskPanelLayout);
		
		//Setup the card layout
		taskPanel.add(mode3Bitmap, TASK_LIST[0]);
		taskPanel.add(mode4PaletteBitmap, TASK_LIST[1]);
		taskPanel.add(mode0Tilemap, TASK_LIST[2]);
		taskPanel.add(mode0PaletteTiles, TASK_LIST[3]);
		
		//Add to the GUI
		mainPanel.add(taskPanel, new CellConstraints("4,7,3,1,fill,fill"));
	}
	
	/**
	 * Sets up the labels in the view
	 */
	public void initLabels() {
		ComponentFactory factory = DefaultComponentFactory.getInstance();
		taskListLabel = factory.createTitle("Task");
		taskPaneLabel = factory.createTitle(TASK_LIST[0]);
		
		//Add to the GUI
		mainPanel.add(taskListLabel, new CellConstraints("2,3,1,1,fill,fill"));
		mainPanel.add(taskPaneLabel, new CellConstraints("4,3,1,1,fill,fill"));
	}
	
	/***************************************************************************
	 * 					   OVERRIDDEN FUNCTIONS METHOD
	 **************************************************************************/
	
	/**
	 * Any time this window is opened anew, we need to set the default options
	 * for the currently selected task
	 */
	@Override
	public void setVisible(final boolean visible) {
		if (visible) {
			updateOptions();
			JGritProperties.getInstance().setProperty(MAIN_GUI_PROPERTY, 
					TASK_GUI);
		}
		
		/*
		 * Since the updates from Option to the Components are being performed
		 * on the event dispatch thread, they were not being completed before
		 * the GUI was made visible. This adds the setVisible to the end of
		 * the queue so that it doesn't get executed until after the option
		 * updates.
		 */
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				GBAExportTaskStyle.super.setVisible(visible);
			}
		});
	}

	/***************************************************************************
	 * 							   MAIN METHOD
	 **************************************************************************/
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				GBAExportTaskStyle inst = new GBAExportTaskStyle();
				inst.setLocationRelativeTo(null);
				inst.setVisible(true);
			}
		});
	}
}